/**
Copyright (C) 2012 Delcyon, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.delcyon.capo.controller.elements;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import com.delcyon.capo.CapoApplication;
import com.delcyon.capo.Configuration.PREFERENCE;
import com.delcyon.capo.controller.AbstractControl;
import com.delcyon.capo.controller.ControlElementProvider;
import com.delcyon.capo.modules.ModuleProvider;
import com.delcyon.capo.resourcemanager.ResourceDescriptor;
import com.delcyon.capo.resourcemanager.ResourceParameter;
import com.delcyon.capo.resourcemanager.ResourceParameterBuilder;
import com.delcyon.capo.resourcemanager.ResourceURI;
import com.delcyon.capo.resourcemanager.ResourceDescriptor.StreamFormat;
import com.delcyon.capo.resourcemanager.ResourceDescriptor.StreamType;
import com.delcyon.capo.resourcemanager.ResourceParameter.Source;
import com.delcyon.capo.resourcemanager.types.FileResourceType;
import com.delcyon.capo.resourcemanager.types.RefResourceType;
import com.delcyon.capo.xml.XPath;
import com.delcyon.capo.xml.XPathFunctionProcessor;
import com.delcyon.capo.xml.XPathFunctionProvider;
import com.delcyon.capo.xml.XPathFunctionUtility;
/**
* @author jeremiah
*
*/
@ControlElementProvider(name="transform")
@XPathFunctionProvider
public class TransformElement extends AbstractControl implements XPathFunctionProcessor
{
private enum Attributes
{
name,ref,stylesheet,type
}
private static final String[] supportedNamespaces = {CapoApplication.SERVER_NAMESPACE_URI};
private static final String[] functionNames = {"transform"};
@Override
public Attributes[] getAttributes()
{
return Attributes.values();
}
@Override
public Attributes[] getRequiredAttributes()
{
return new Attributes[]{Attributes.name,Attributes.ref,Attributes.stylesheet};
}
@Override
public String[] getSupportedNamespaces()
{
return supportedNamespaces;
}
@Override
public String[] getXPathFunctionNames()
{
return functionNames;
}
@Override
public Object processFunction(String functionName, Object... arguments) throws Exception
{
Node contextNode = getContextNode();
String prefix = XPathFunctionUtility.getPrefix(contextNode, arguments, 1);
if (functionName.equals("transform"))
{
return "//"+prefix+"transform[@name = '"+arguments[0]+"']";
}
else
{
return null;
}
}
@Override
public Object processServerSideElement() throws Exception
{
String ref = getAttributeValue(Attributes.ref);
String stylesheet = getAttributeValue(Attributes.stylesheet);
String src = null;
//see if we are making a specific reference to something, and if so ues it, as opposed to the module system.
if (ResourceURI.getScheme(stylesheet) != null)
{
src = stylesheet;
}
Node refNode = XPath.selectSingleNode(getControlElementDeclaration(), ref);
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = null;
if (src != null)
{
ResourceDescriptor resourceDescriptor = getParentGroup().getResourceDescriptor(this, src);
resourceDescriptor.addResourceParameters(getParentGroup(),new ResourceParameter(FileResourceType.Parameters.PARENT_PROVIDED_DIRECTORY,PREFERENCE.MODULE_DIR,Source.CALL));
resourceDescriptor.addResourceParameters(getParentGroup(),new ResourceParameter(RefResourceType.Parameters.XMLNS,"xsl=http://www.w3.org/1999/XSL/Transform"));
if (resourceDescriptor.isSupportedStreamFormat(StreamType.INPUT, StreamFormat.XML_BLOCK))
{
Element styleSheetElement = resourceDescriptor.readXML(getParentGroup(),ResourceParameterBuilder.getResourceParameters(getControlElementDeclaration()));
Document transformDocument = CapoApplication.getDocumentBuilder().newDocument();
Element transformStyleSheetElement = (Element) transformDocument.adoptNode(styleSheetElement);
transformDocument.appendChild(transformStyleSheetElement);
//for some reason, we always strip out the parent name space if it's declared in the child, which it has to be, so we add it back in.
String parentNameSpace = getControlElementDeclaration().getNamespaceURI();
String parentPrefix = getControlElementDeclaration().getPrefix();
transformStyleSheetElement.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:"+parentPrefix, parentNameSpace);
transformer = tFactory.newTransformer(new DOMSource(transformDocument));
}
else
{
transformer = tFactory.newTransformer(new StreamSource(resourceDescriptor.getInputStream(getParentGroup(),ResourceParameterBuilder.getResourceParameters(getControlElementDeclaration()))));
}
//cleanup and parameters we added when calling this.
resourceDescriptor.close(getParentGroup(),ResourceParameterBuilder.getResourceParameters(getControlElementDeclaration()));
}
else if (stylesheet.isEmpty() == false)
{
Element moduleElement = ModuleProvider.getModuleElement(stylesheet);
if (moduleElement == null)
{
throw new Exception ("Couldn't locate a style sheet named "+stylesheet+" in any of the module directories");
}
Document transformDocument = CapoApplication.getDocumentBuilder().newDocument();
Element transformStyleSheetElement = (Element) transformDocument.adoptNode(moduleElement);
transformDocument.appendChild(transformStyleSheetElement);
//for some reason, we always strip out the parent name space if it's declared in the child, which it has to be, so we add it back in.
String parentNameSpace = getControlElementDeclaration().getNamespaceURI();
String parentPrefix = getControlElementDeclaration().getPrefix();
transformStyleSheetElement.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:"+parentPrefix, parentNameSpace);
transformer = tFactory.newTransformer(new DOMSource(transformDocument));
}
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(new DOMSource(refNode), new DOMResult(getControlElementDeclaration()));
if (getControlElementDeclaration().hasAttribute(Attributes.name.toString()))
{
getParentGroup().set(getAttributeValue(Attributes.name), XPath.getXPath(getControlElementDeclaration()));
}
return null;
}
}